package net.xdclass.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import net.xdclass.config.MqConfig;
import net.xdclass.enums.BizCodeEnum;
import net.xdclass.enums.CouponStateEnum;
import net.xdclass.enums.ProductOrderStateEnum;
import net.xdclass.enums.StockTaskStateEnum;
import net.xdclass.exception.BizException;
import net.xdclass.feign.OrderFeignClient;
import net.xdclass.interceptor.LoginInterceptor;
import net.xdclass.mapper.CouponTaskMapper;
import net.xdclass.model.CouponRecordDO;
import net.xdclass.mapper.CouponRecordMapper;
import net.xdclass.model.CouponRecordMessage;
import net.xdclass.model.CouponTaskDO;
import net.xdclass.model.LoginUser;
import net.xdclass.request.LockCouponRecordRequest;
import net.xdclass.service.CouponRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.xdclass.util.JsonData;
import net.xdclass.vo.CouponRecordVo;
import org.checkerframework.checker.units.qual.A;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 孙浩
 * @since 2022-04-20
 */
@Slf4j
@Service
public class CouponRecordServiceImpl extends ServiceImpl<CouponRecordMapper, CouponRecordDO> implements CouponRecordService {
  @Autowired
  private CouponRecordMapper couponRecordMapper;

  @Autowired
  private CouponTaskMapper couponTaskMapper;

  @Autowired
  private RabbitTemplate rabbitTemplate;

  @Autowired
  private MqConfig mqConfig;

  @Autowired
  private OrderFeignClient orderFeignClient;

  @Override
  public Map<String, Object> pageData(int page, int size) {
    LoginUser loginUser = LoginInterceptor.threadLocal.get();
    Page<CouponRecordDO> pageInfo = new Page<>(page, size);
    Page<CouponRecordDO> recordDOPage = couponRecordMapper.selectPage(pageInfo, new QueryWrapper<CouponRecordDO>().eq("user_id", loginUser.getId()).orderByDesc("create_time"));
    Map<String, Object> pageMap = new HashMap<>(3);
    pageMap.put("total_record", recordDOPage.getTotal());
    pageMap.put("total_page", recordDOPage.getPages());
    pageMap.put("current_data", recordDOPage.getRecords().stream().map(obj -> beanProcess(obj)).collect(Collectors.toList()));
    return pageMap;
  }

  private CouponRecordVo beanProcess(CouponRecordDO couponRecordDO) {
    CouponRecordVo couponRecordVo = new CouponRecordVo();
    BeanUtils.copyProperties(couponRecordDO, couponRecordVo);
    return couponRecordVo;
  }

  @Override
  public CouponRecordVo findById(long recordId) {
    LoginUser loginUser = LoginInterceptor.threadLocal.get();
    CouponRecordDO couponRecordDO = couponRecordMapper.selectOne(new QueryWrapper<CouponRecordDO>().eq("id", recordId).eq("user_id", loginUser.getId()));
    if (couponRecordDO == null) {
      return null;
    }
    return beanProcess(couponRecordDO);
  }

  @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
  @Override
  public JsonData lockRecords(LockCouponRecordRequest couponRecordRequest) {
    LoginUser loginUser = LoginInterceptor.threadLocal.get();

    List<Long> lockCouponRecordIds = couponRecordRequest.getLockCouponRecordIds();

    // 修改使用状态为 已使用
    int lockRows = couponRecordMapper.lockUseStateBatch(loginUser.getId(), CouponStateEnum.USED.name(), lockCouponRecordIds);

    //保存优惠券使用锁定记录
    List<CouponTaskDO> couponTaskDOList = lockCouponRecordIds.stream().map(couponRecordId -> {
      CouponTaskDO couponTaskDO = new CouponTaskDO();
      couponTaskDO.setCouponRecordId(couponRecordId);
      couponTaskDO.setCreateTime(new Date());
      couponTaskDO.setOutTradeNo(couponRecordRequest.getOrderOutTradeNo());
      couponTaskDO.setLockState(StockTaskStateEnum.LOCK.name());
      return couponTaskDO;
    }).collect(Collectors.toList());

    int insertRows = couponTaskMapper.insertBatch(couponTaskDOList);

    log.info("优惠券锁定记录 lockRows{}", lockRows);
    log.info("保存优惠券使用锁定记录 insertRows{}", insertRows);

    if (insertRows == lockCouponRecordIds.size() && insertRows == lockRows) {
      //发送延迟消息
      for (CouponTaskDO couponTaskDO : couponTaskDOList) {
        CouponRecordMessage couponRecordMessage = new CouponRecordMessage();
        couponRecordMessage.setTaskId(couponTaskDO.getId());
        couponRecordMessage.setOutTradeNo(couponRecordRequest.getOrderOutTradeNo());
        rabbitTemplate.convertAndSend(mqConfig.getEventExchange(), mqConfig.getCouponReleaseDelayRoutingKey(), couponRecordMessage);
        log.info("优惠券锁定消息发送成功:{}", couponRecordMessage);
      }
      return JsonData.buildSuccess();
    } else {
      return JsonData.buildResult(BizCodeEnum.COUPON_RECORD_LOCK_FAIL);
    }
  }

  @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
  @Override
  public boolean releaseCouponRecord(CouponRecordMessage recordMessage) {
    CouponTaskDO couponTaskDO = couponTaskMapper.selectById(recordMessage.getTaskId());
    if (null == couponTaskDO) {
      log.info("工作单不存在 消息{}", recordMessage);
      return true;
    }
    if (couponTaskDO.getLockState().equalsIgnoreCase(StockTaskStateEnum.LOCK.name())) {
      //需要根据订单状态 修改不同的状态
      JsonData jsonData = orderFeignClient.queryProductOrderState(recordMessage.getOutTradeNo());
      if (jsonData.getCode() == 0) {
        String orderState = jsonData.getData().toString();
        if (orderState.equalsIgnoreCase(ProductOrderStateEnum.NEW.name())) {
          //订单状态为NEW 状态 需要重新投递
          log.warn("订单状态是NEW状态 重新投递{}", recordMessage);
          return false;
        }
        if (orderState.equalsIgnoreCase(ProductOrderStateEnum.PAY.name())) {
          //订单状态为PAY 状态 需要修改工作单状态为 完成
          couponTaskDO.setLockState(StockTaskStateEnum.FINISH.name());
          couponTaskMapper.update(couponTaskDO, new QueryWrapper<CouponTaskDO>().eq("id", couponTaskDO.getId()));
          log.warn("订单已经支付 修改工作单状态为完成 {}", recordMessage);
          return true;
        }
      }
      //订单状态为CANCEL 状态 需要修改工作单状态为 取消 同时修改优惠券记录为NEW
      log.warn("订单不存在 或者 已经取消 修改工作单状态为取消 {}", recordMessage);
      couponTaskDO.setLockState(StockTaskStateEnum.CANCEL.name());
      couponTaskMapper.update(couponTaskDO, new QueryWrapper<CouponTaskDO>().eq("id", couponTaskDO.getId()));
      couponRecordMapper.updateState(couponTaskDO.getCouponRecordId(), CouponStateEnum.NEW.name());
    } else {
      log.info("工作单已经处理完毕 状态{} 消息体{}", couponTaskDO.getLockState(), recordMessage);
    }
    return true;
  }
}
